#define _GNU_SOURCE
#include "app_serial.h"
#include "log/log.h"
#include <stdlib.h>
#include "app_bluetooth.h"
#include "unistd.h"

static int set_block_mode(SerialDevice *serial, int is_block)
{
    struct termios termios;

    // 获取串口属性
    if (tcgetattr(serial->super.fd, &termios) != 0)
    {
        log_error("tcgetattr error");
        return -1;
    }
    // 修改属性 阻塞非阻塞模式
    if (is_block)
    {
        termios.c_cc[VMIN] = 1;
        termios.c_cc[VTIME] = 0;
    }
    else
    {
        termios.c_cc[VMIN] = 0;
        termios.c_cc[VTIME] = 2;
    }

    if (tcsetattr(serial->super.fd, TCSAFLUSH, &termios) != 0)
    {
        log_error("tcsetattr error");
        return -1;
    }

    return 0;
}

static int make_raw(SerialDevice *serial)
{
    struct termios termios;

    // 获取串口属性
    if (tcgetattr(serial->super.fd, &termios) != 0)
    {
        log_error("tcgetattr error");
        return -1;
    }
    // 修改属性 原始模式
    cfmakeraw(&termios);
    if (tcsetattr(serial->super.fd, TCSAFLUSH, &termios) != 0)
    {
        log_error("tcsetattr error");
        return -1;
    }

    return 0;
}

SerialDevice *app_serial_init(char *filename)
{
    // 初始化设备
    Device *device = app_device_init(filename);
    if (!device)
    {
        log_error("app_serial_init: app_device_init failed");
        goto DEVICE_INIT_FALL;
    }

    // 在设备内存基础上扩展出一个串口设备内存
    SerialDevice *serial = realloc(device, sizeof(SerialDevice));
    if (!serial)
    {
        log_error("realloc SerialDevice error");
        goto SERIAL_INIT_FALL;
    }

    // 设置为原始模式
    if (make_raw(serial) != 0)
    {
        log_error("make_raw failed");
        goto SERIAL_INIT_FALL;
    }

    if (app_serial_setBraudRate(serial, BR_115200) != 0)
    {
        log_error("app_serial_setBraudRate failed");
        goto SERIAL_INIT_FALL;
    }

    if (app_serial_setParity(serial, Parity_None) != 0)
    {
        log_error("app_serial_setParity failed");
        goto SERIAL_INIT_FALL;
    }
    if (app_serial_setStopBits(serial, StopBits_1) != 0)
    {
        log_error("app_serial_setStopBits failed");
        goto SERIAL_INIT_FALL;
    }
    // 让前面设置的所有属性生效
    tcflush(serial->super.fd, TCIFLUSH);

    return serial;

SERIAL_INIT_FALL:
    app_device_close(device);
DEVICE_INIT_FALL:
    return NULL;
}

int app_serial_setBraudRate(SerialDevice *serial, BraudRate braud_rate)
{
    serial->braud_rate = braud_rate;
    struct termios termios;

    // 获取串口属性
    if (tcgetattr(serial->super.fd, &termios) != 0)
    {
        log_error("tcgetattr error");
        return -1;
    }

    // 修改属性 波特率
    // cfsetispeed(&termios, braud_rate);
    // cfsetospeed(&termios, braud_rate);
    cfsetispeed(&termios, braud_rate);
    // 设置串口属性 只有调用flush之后才会生效
    if (tcsetattr(serial->super.fd, TCSAFLUSH, &termios) != 0)
    {
        log_error("tcsetattr error");
        return -1;
    }

    return 0;
}

int app_serial_setParity(SerialDevice *serial, Parity parity)
{
    serial->parity = parity;
    struct termios termios;

    // 获取串口属性
    if (tcgetattr(serial->super.fd, &termios) != 0)
    {
        log_error("tcgetattr error");
        return -1;
    }

    // 修改属性 波特率
    termios.c_cflag &= ~(PARENB | PARODD); // 清除校验位
    termios.c_iflag |= parity;             // 忽略校验错误
    // 设置串口属性 只有调用flush之后才会生效
    if (tcsetattr(serial->super.fd, TCSAFLUSH, &termios) != 0)
    {
        log_error("tcsetattr error");
        return -1;
    }

    return 0;
}

int app_serial_setStopBits(SerialDevice *serial, Stopbits stop_bits)
{
    serial->stop_bits = stop_bits;
    struct termios termios;

    // 获取串口属性
    if (tcgetattr(serial->super.fd, &termios) != 0)
    {
        log_error("tcgetattr error");
        return -1;
    }

    // 修改属性 停止位
    termios.c_cflag &= ~CSTOPB;   // 清除停止位
    termios.c_cflag |= stop_bits; // 设置停止位

    // 设置串口属性 只有调用flush之后才会生效
    if (tcsetattr(serial->super.fd, TCSAFLUSH, &termios) != 0)
    {
        log_error("tcsetattr error");
        return -1;
    }

    return 0;
}

int app_serial_setConnectType(SerialDevice *serial, ConnectionType conn_type)
{
    serial->super.conn_type = conn_type; // 设置连接类型
    // 将串口的波特率设置为9600尝试与蓝牙连接
    app_serial_setBraudRate(serial, BR_9600);
    // 将串口设置为非阻塞模式---》如果蓝牙没有连接上，返回-1
    set_block_mode(serial, 0);
    tcflush(serial->super.fd, TCIFLUSH);
    if (app_bluetooth_status((Device *)serial) != 0)
    {
        // 初始化蓝牙
        app_bluetooth_rename(serial, "shuangzi");
        app_bluetooth_setBaudrate(serial, BT_BR_115200);
        app_bluetooth_setNetID((Device *)serial, "1234");
        app_bluetooth_setMaddr((Device *)serial, "3442");
        app_bluetooth_reset((Device *)serial);
        // 等待a蓝牙重启
        sleep(1);
    }
    // 将串口的波特率设置为9600尝试与蓝牙连接
    app_serial_setBraudRate(serial, BR_115200);
    if (tcflush(serial->super.fd, TCIFLUSH) != 0)
    {
        log_error("tcflush error");
        return -1;
    }
    // 给设备指定postRead和postWrite
    serial->super.funs->post_read = app_bluetooth_postRead;
    serial->super.funs->pre_write = app_bluetooth_preWrite;

    // 完成设置后将串口设置为阻塞模式
    set_block_mode(serial, 1);
    tcflush(serial->super.fd, TCIFLUSH);
    return 0;
}
